﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmCommunicationProtocolData.h"
#include "IIODevice.h"
#include "IIOStream.h"
#include "NdbClassSchemaLibraryOfCode.h"
#include "RawMemory.h"
#include "IDbObjectArchiveUtils.h"
#include "NdbObject.h"
#include "IDbObject.h"
#include "TransferOwnership.h"
#include "GbmpNew.h"
#include "DebugMessage.h"
#include "StringUtil.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    class CommunicationProtocolData : public ICommunicationProtocolData
    {
    public:
        CommunicationProtocolData(CommunicationIOMode ioMode);
        virtual ~CommunicationProtocolData() {}

        //获取数据
        virtual const char *GetData() const override;
        virtual uint32_t GetDataSize() const override;
        virtual CommunicationProtocolDataType GetDataType() const override;
        virtual std::wstring GetDataAsSharedMemoryKey() const override;
        virtual gcmp::OwnerPtr<gcmp::NdbObject> GetDataAsNdbObject() const override;

        virtual bool SetData(const std::wstring& sharedMemoryKey)override;
        virtual bool SetData(const gcmp::NdbObject* pData) override;
        virtual bool SetRawData(const char* pData, int dataLength) override;

        bool ReAllocate(uint32_t size);
    private:
        OwnerPtr<IIODevice> m_opData;
        std::vector<char> m_dataBuffer;
        uint32_t m_dataSize;
        CommunicationIOMode m_ioMode;
    };
}

CommunicationProtocolData::CommunicationProtocolData(CommunicationIOMode ioMode)
    : m_ioMode(ioMode)
    , m_dataSize(0)
{
}

bool CommunicationProtocolData::ReAllocate(uint32_t size)
{
    if (size <= m_dataBuffer.size())
    {
        return true;
    }
    m_dataBuffer.resize(size);
    m_dataSize = 0;
    if (m_ioMode == CommunicationIOMode::Load)
    {
        m_opData = IIODevice::CreateMemoryIODeviceForLoad(m_dataBuffer.data(), (uint32_t)m_dataBuffer.size());
    }
    else if (m_ioMode == CommunicationIOMode::Store)
    {
        m_opData = IIODevice::CreateMemoryIODeviceForStore(m_dataBuffer.data(), (uint32_t)m_dataBuffer.size());
    }
    else
    {
        DBG_WARN(L"未知类型" + StringUtil::ToWString((int)m_ioMode),L"GDMPLab",L"2024-03-30");
        return false;
    }

    return true;
}

const char* CommunicationProtocolData::GetData() const
{
    return m_dataBuffer.data();
}

uint32_t CommunicationProtocolData::GetDataSize() const
{
    return m_dataSize;
}

CommunicationProtocolDataType CommunicationProtocolData::GetDataType() const
{
    if (GetDataSize() < 4)
    {
        return CommunicationProtocolDataType::Invalid;
    }
    IIODevice* pDevice = const_cast<IIODevice*>(m_opData.get());
    pDevice->Seek(0);
    OwnerPtr<IIOStream> opStream = IIOStream::CreateIOStream(const_cast<IIODevice*>(m_opData.get()));
    int32_t typeValue = 0;
    (*opStream) >> typeValue;
    return CommunicationProtocolDataType(typeValue);
}

std::wstring CommunicationProtocolData::GetDataAsSharedMemoryKey() const
{
    if (GetDataSize() < 4)
    {
        return std::wstring();
    }
    IIODevice* pDevice = const_cast<IIODevice*>(m_opData.get());
    pDevice->Seek(0);
    OwnerPtr<IIOStream> opStream = IIOStream::CreateIOStream(const_cast<IIODevice*>(m_opData.get()));
    int32_t typeValue = 0;
    (*opStream) >> typeValue;
    if (typeValue != (int32_t)CommunicationProtocolDataType::SharedMemoryData)
    {
        return std::wstring();
    }
    std::wstring memoryKey;
    opStream->ReadString(memoryKey);
    return memoryKey;
}

gcmp::OwnerPtr<gcmp::NdbObject> CommunicationProtocolData::GetDataAsNdbObject() const
{
    if (GetDataSize() < 4)
    {
        return nullptr;
    }
    IIODevice* pDevice = const_cast<IIODevice*>(m_opData.get());
    pDevice->Seek(0);
    OwnerPtr<IIOStream> opStream = IIOStream::CreateIOStream(const_cast<IIODevice*>(m_opData.get()));
    int32_t typeValue = 0;
    (*opStream) >> typeValue;
    if (typeValue != (int32_t)CommunicationProtocolDataType::NdbObjectData)
    {
        return nullptr;
    }

    int dataLength = GetDataSize() - (int32_t)pDevice->Pos();
    std::vector<char> buffer(dataLength);
    opStream->Read(buffer.data(), dataLength);
    bool isOk = false;
    std::wstring errorMsg;
    OwnerPtr<IDbObject> opDbObject = IDbObjectArchiveUtils::LoadDbObject(buffer, isOk, &errorMsg);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(isOk && opDbObject, L"DbObject反序列化失败："+errorMsg,L"GDMPLab",L"2024-03-30");

    OwnerPtr<NdbObject> opObject = TransferOwnershipCast<NdbObject>(opDbObject);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opObject, L"反序列化的对象只支持NdbObject类型",L"GDMPLab",L"2024-03-30");

    return opObject;
}

bool CommunicationProtocolData::SetData(const std::wstring& sharedMemoryKey)
{
    int maxStrSize = (int)sharedMemoryKey.size() * 3 + 12;
    ReAllocate(maxStrSize);

    m_opData->Seek(0);
    OwnerPtr<IIOStream> opStream = IIOStream::CreateIOStream(const_cast<IIODevice*>(m_opData.get()));
    (*opStream) << (int32_t)CommunicationProtocolDataType::SharedMemoryData;

    opStream->WriteString(sharedMemoryKey);

    DBG_WARN_AND_RETURN_FALSE_UNLESS(maxStrSize >= m_opData->Pos(), L"分配的缓存不够大。",L"GDMPLab",L"2024-03-30");
    m_dataSize = (uint32_t)m_opData->Pos();

    return true;
}

bool CommunicationProtocolData::SetData(const gcmp::NdbObject* pObject)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pObject, L"pObject为空。",L"GDMPLab",L"2024-03-30");

    const IDbObject* pDbObject = quick_cast<IDbObject>(pObject);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDbObject, L"只有IDbObject类型的对象才支持流化。",L"GDMPLab",L"2024-03-30");
    std::vector<char> buffer;
    std::wstring errorMsg;
    bool isOk = IDbObjectArchiveUtils::StoreDbObject(pDbObject, buffer, &errorMsg);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(isOk, L"写对象到缓存中出错："+ errorMsg,L"GDMPLab",L"2024-03-30");

    int maxStrSize = (int)buffer.size() + 4;
    ReAllocate(maxStrSize);

    m_opData->Seek(0);
    OwnerPtr<IIOStream> opStream = IIOStream::CreateIOStream(const_cast<IIODevice*>(m_opData.get()));
    (*opStream) << (int32_t)CommunicationProtocolDataType::NdbObjectData;

    opStream->Write(buffer.data(), (int)buffer.size());

    DBG_WARN_AND_RETURN_FALSE_UNLESS(maxStrSize >= m_opData->Pos(), L"分配的缓存不够大。",L"GDMPLab",L"2024-03-30");
    m_dataSize = (uint32_t)m_opData->Pos();

    return true;
}

bool CommunicationProtocolData::SetRawData(const char* pData, int dataLength)
{
    int maxStrSize = dataLength;
    ReAllocate(maxStrSize);

    m_opData->Seek(0);
    m_opData->Write(pData, dataLength);

    DBG_WARN_AND_RETURN_FALSE_UNLESS(maxStrSize >= m_opData->Pos(), L"分配的缓存不够大。",L"GDMPLab",L"2024-03-30");
    m_dataSize = (uint32_t)m_opData->Pos();

    return true;
}

OwnerPtr<ICommunicationProtocolData> gcmp::ICommunicationProtocolData::Create(CommunicationIOMode ioMode)
{
    return NEW_AS_OWNER_PTR(CommunicationProtocolData, ioMode);
}
